package cn.bonoon.services.plugins;

import java.util.Collection;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import cn.bonoon.core.IAccountEditor;
import cn.bonoon.core.plugins.AccountService;
import cn.bonoon.core.plugins.LoginService;
import cn.bonoon.entities.plugins.AccountEntity;
import cn.bonoon.entities.plugins.RoleAssignEntity;
import cn.bonoon.entities.plugins.RoleEntity;
import cn.bonoon.entities.plugins.ShortcutMenuEntity;
import cn.bonoon.kernel.events.OperateEvent;
import cn.bonoon.kernel.exceptions.PasswordVerifierException;
import cn.bonoon.kernel.menus.ChannelInfo;
import cn.bonoon.kernel.menus.IModuleInfo;
import cn.bonoon.kernel.menus.ItemInfo;
import cn.bonoon.kernel.menus.TabInfo;
import cn.bonoon.kernel.security.PrivilegeChecker;
import cn.bonoon.kernel.security.PrivilegeInfo;
import cn.bonoon.kernel.support.IOperator;
import cn.bonoon.kernel.support.PasswordVerifier;
import cn.bonoon.kernel.support.services.AbstractService;

@Service
@Transactional(readOnly = true)
public class AccountServiceImpl extends AbstractService<AccountEntity> implements AccountService, LoginService {
	private final PasswordVerifier passwordVerifier;

	@Autowired
	public AccountServiceImpl(PasswordVerifier passwordVerifier) {
		this.passwordVerifier = passwordVerifier;
	}

	// ////////////////======================================================
	@Override
	@Transactional
	protected AccountEntity __save(OperateEvent event, AccountEntity entity) {
		IAccountEditor pe = (IAccountEditor) event.getSource();
		passwordVerifier.set(entity, pe);
		
		AccountEntity _entity = super.__save(event, entity);
		Long[] roles = pe.getRoles();
		if (null != roles && roles.length > 0) {
			for (Long role : roles) {
				RoleAssignEntity rae = new RoleAssignEntity();
				rae.setAccount(_entity);
				rae.setRole(entityManager.find(RoleEntity.class, role));
				rae.setCreateAt(event.now());
				rae.setCreatorId(event.getId());
				entityManager.persist(rae);
			}
		}
		return _entity;
	}

	@Override
	@Transactional
	public void modify(Long uid, String oldPwd, String newPwd, String repwd) throws PasswordVerifierException {
		AccountEntity ae = __get(uid);
		passwordVerifier.resetPassword(ae, oldPwd, newPwd, repwd);
		ae.setForcedChangePwd(false);
		entityManager.merge(ae);
	}

//	@Override
//	public List<ShortcutMenuEntity> getHostShortcutMenus() {
//		// TODO Auto-generated method stub
//		return null;
//	}

	@SuppressWarnings("unchecked")
	@Override
	public List<ShortcutMenuEntity> shortcutMenus(IOperator opt, String moduleId) {
		Long uid = opt.getId();
		
//		String rids;
//		String ql_role = "select distinct x.role.id from RoleAssignEntity x where x.account.id=?";
//		List<Long> rold_ids = __list(Long.class, ql_role, uid);
//		int size = rold_ids.size();
//		if (size == 1) {
//			rids = "x.role.id=" + rold_ids.get(0);
//		} else if (size > 1) {
//			StringBuilder sb = new StringBuilder();
//			for (Long rid : rold_ids) {
//				sb.append(',').append(rid);
//			}
//			rids = "x.role.id in(" + sb.substring(1) + ")";
//		} else {
//			rids = "x.role.id=-1";
//		}
//
//		String ql_privilege = "select distinct x.meunId from BasePrivilegeEntity x where x.account.id=? or " + rids;
//		List<String> privilege_ids = __list(String.class, ql_privilege, uid);
//
//		String ql_menu = "from ShortcutMenuEntity x where x.owner=? and x.moduleId=? order by x.ordinal asc, x.createAt asc";
//		List<ShortcutMenuEntity> menus = __list(ShortcutMenuEntity.class, ql_menu, uid, moduleId);
//		
//		Iterator<ShortcutMenuEntity> iter = menus.iterator();
//		while (iter.hasNext()) {
//			ShortcutMenuEntity menu = iter.next();
//			if (!privilege_ids.contains(menu.getMenuId())) {
//				iter.remove();
//			}
//		}
//		return menus;
		//如果是超级管理员，则不需要连表判断
		if(opt.isSuper()){
			String ql = "select x from ShortcutMenuEntity x where x.owner=? and x.moduleId=? order by x.ordinal asc";
			return entityManager.createQuery(ql, ShortcutMenuEntity.class).setParameter(1, uid).setParameter(2, moduleId).getResultList();
		}
		String sql = "select x.* from T_SHORTCUTMENU x inner join T_PRIVILEGE y on x.C_MENUID=y.C_MENUID";
		sql += " inner join T_ROLEASSIGN z on (y.R_ROLE_ID=z.R_ROLE_ID or y.R_ACCOUNT_ID=z.R_ACCOUNT_ID) and x.C_OWNER=z.R_ACCOUNT_ID";
		sql += " where x.C_OWNER=? and x.C_MODULEID=? order by x.C_ORDINAL asc, x.C_CREATEAT asc";
		return entityManager.createNativeQuery(sql, ShortcutMenuEntity.class).setParameter(1, uid).setParameter(2, moduleId).getResultList();
	}

	@Override
	@Transactional
	public String resetPassword(Long id, String pwd, String repwd, boolean enforce) throws PasswordVerifierException {
		AccountEntity ae = get(id);
		passwordVerifier.setPassword(ae, pwd, repwd);
		ae.setForcedChangePwd(enforce);
		entityManager.merge(ae);
		return pwd;
	}

	@Override
	@Transactional
	public String randomPassword(Long id, boolean enforce) throws PasswordVerifierException {
		AccountEntity ae = get(id);
		String pwd = passwordVerifier.randomPassword(ae);
		ae.setForcedChangePwd(enforce);
		entityManager.merge(ae);
		return pwd;
	}

	private final String _0 = "select x from AccountEntity x where x.deleted=false and x.loginName=?";
	@Override
	public AccountEntity loadByLoginName(String loginName) {
		return __first(domainClass, _0, loginName);
	}

	private final String _1 = "select distinct  x.role.moduleKey from RoleAssignEntity x where x.account.id=?";
	@Override
	public Collection<String> accessableModules(IOperator user) {
		return __list(String.class, _1, user.getId());
	}

	@Override
	public List<Long> getActions(ItemInfo item, IOperator user) {
		Long uid = user.getId();
		String roleql = __role(item.getModule().getId(), uid);
		String ql = "select x.actions from PrivilegeEntity x where x.meunId=? and " + roleql;
		return __list(Long.class, ql, item.getId());
	}

	private PrivilegeChecker __privilege(IOperator user, String mid, String cid, String pid) {
		if (user.isSuper()) {
			return PrivilegeChecker.ALL;
		}

		Long uid = user.getId();
		String roleql = __role(mid, uid);
		String cql = "select distinct x.channelId from BasePrivilegeEntity x where x.moduleId=? and x.account.id=? or " + roleql;
		String mql = "select distinct x.meunId from BasePrivilegeEntity x where x.moduleId=? and x.account.id=? or " + roleql;

		return new PrivilegeInfo(mid, cid, pid, __list(String.class, cql, mid, uid), __list(String.class, mql, mid, uid));
	}

	private final String _2 = "select distinct x.role.id from RoleAssignEntity x where x.role.moduleKey=? and x.account.id=?";
	private String __role(String mid, Long uid) {
		List<Long> rids = __list(Long.class, _2, mid, uid);
		int size = rids.size();
		if (size == 1) {
			return "x.role.id=" + rids.get(0);
		}
		if (size > 1) {
			StringBuilder sb = new StringBuilder();
			for (Long rid : rids) {
				sb.append(',').append(rid);
			}
			return "x.role.id in(" + sb.substring(1) + ")";
		}
		return "x.role.id=-1";
	}

	@Override
	public PrivilegeChecker privilege(IOperator user, ItemInfo item) {
		String pid = item.getId(); // F0E2761FA4FACB39260838964D2910E1
		String cid = item.getChannel().getId(); // 9BAE24200416CF92AF47B1BC137E9E41
		String mid = item.getModule().getId(); // 66CD9CB1900481637F0C9DECC65A05F0
		return __privilege(user, mid, cid, pid);
	}

	@Override
	public PrivilegeChecker privilege(IOperator user, TabInfo tab) {
		String pid = tab.getId();
		String cid = tab.getChannel().getId();
		String mid = tab.getModule().getId();
		return __privilege(user, mid, cid, pid);
	}

	@Override
	public PrivilegeChecker privilege(IOperator user, IModuleInfo module) {
		return __privilege(user, module.getId(), null, null);
	}

	@Override
	public PrivilegeChecker privilege(IOperator user, String mid, String cid) {
		return __privilege(user, mid, cid, cid);
	}
	
	private final String _3 = "select distinct x.role.roleKey from RoleAssignEntity x where x.account.id=?";
	@Override
	public List<String> getRoleKeys(Long uid) {
		return __list(String.class, _3, uid);
	}

	private final String _4 = "select distinct x.meunId from AccountPrivilegeEntity x where x.moduleId=? and x.channelId=? and x.account.id=?";
	@Override
	public List<String> getMenuIds(Long userId, ChannelInfo item) {
		return __list(String.class, _4, item.getModule().getId(), item.getId(), userId);
	}

	@Override
	public AccountEntity findAccountByLoginName(String userAccount) {
		// TODO Auto-generated method stub
		return this.__first(AccountEntity.class, String.format("select x from AccountEntity x where x.loginName='%s'",userAccount));
	}

}
